package com.znsd.zl.app.user.service.impl;

import com.baidu.aip.ocr.AipOcr;
import com.google.gson.internal.$Gson$Preconditions;
import com.znsd.zl.app.ocr.entity.IdCardBackEntity;
import com.znsd.zl.app.ocr.entity.IdCardEntity;
import com.znsd.zl.app.ocr.utils.JsonUtils;
import com.znsd.zl.app.ocr.utils.OcrConstants;
import com.znsd.zl.app.user.utils.AesUtils;
import com.znsd.zl.app.user.vo.req.RecognitionIdCardInfoReqVO;
import com.znsd.zl.exception.RRException;
import com.znsd.zl.utils.R;
import org.apache.shiro.codec.Base64;
import org.json.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.znsd.zl.app.ocr.service.IOcrService;
import com.znsd.zl.app.user.dao.IAppUserDao;
import com.znsd.zl.app.user.entity.AppUserEntity;
import com.znsd.zl.app.user.service.IAppUserService;
import com.znsd.zl.app.user.utils.JwtUtils;
import com.znsd.zl.app.user.utils.LoginCredentialsUtils;
import com.znsd.zl.app.user.utils.RedisUtils;
import com.znsd.zl.app.user.vo.req.AppUserRealAuthReqVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.util.Date;
import java.util.Map;

/**
 *  <p>
 *      客户端用户业务层接口实现类
 *  </p>
 * @ClassName AppUserServiceImpl
 * @Description 用户业务层接口实现类
 * @author jaypdd
 * @email jaypdd@163.com
 * @date 2020-08-21 17:26:01
 * @Version v1.0
 */
@Slf4j
@Service("appUserService")
public class AppUserServiceImpl extends ServiceImpl<IAppUserDao, AppUserEntity> implements IAppUserService {

	@Resource
	private LoginCredentialsUtils loginCredentialsUtils;

	@Resource
	private JwtUtils jwtUtils;

	@Resource
	private RedisUtils redisUtils;

	@Resource
	private IOcrService ocrService;

	@Resource
	private JsonUtils jsonUtils;

	@Resource
	private IAppUserService userService;

	@Resource
	private AipOcr aipOcr;

	/**
	 * 根据openid获取用户信息
	 * @param openId openid
	 * @return       返回对应单个用户信息对象
	 */
	@Override
	public AppUserEntity findAppUserByOpenId(String openId) {
		return super.baseMapper.findUserByOpenId(openId);
	}

	/**
	 * 用户登录
	 * @param code  登录临时凭证换取openid进行登录
	 * @return      返回token
	 */
	@Override
	public String login(String code) {
		// 获取凭证
		Map<String, Object> map = loginCredentialsUtils.getCredentials(code).getInnerMap();
		String openId = (String) map.get("openid");
		String sessionKey = (String) map.get("session_key");

		// 根据openid获取用户信息，判断用户是否注册
		AppUserEntity user = super.baseMapper.findUserByOpenId(openId);
		if ( null == user ) {
			user = new AppUserEntity().setOpenId(openId).setHouseNumber(0)
					.setUserStatus(25).setCreateTime(new Date());
			super.save(user);
		}
		// 创建token
		return jwtUtils.createToken(user.getUserId(), openId, sessionKey);
	}

	/**
	 * 获取当前登录的用户信息
	 * @param token token
	 * @return      返回用户信息
	 */
	@Override
	public AppUserEntity getUserInfo(String token) {
		// token解密
		String[] tokenInfo = jwtUtils.tokenDecode(token);
		if ( tokenInfo != null ) {
			String userId = tokenInfo[0];
			return super.baseMapper.selectById(userId);
		}
		return null;
	}

	/**
	 * 根据当前请求token更新用户信息
	 * @param newUser  需要完善的用户信息
	 * @param token    token
	 * @return         成功true，失败false
	 */
	@Override
	public boolean updateInfo(AppUserEntity newUser, String token) {
		String[] tokenInfo = jwtUtils.tokenDecode(token);
		if ( tokenInfo != null ) {
			String userId = tokenInfo[0];
			boolean status = super.updateById(newUser.setUserId(Integer.parseInt(userId)));
			// 更新缓存中的用户信息
			if ( status && token != null ) {
				redisUtils.delete(userId);
				redisUtils.set(userId, newUser.setOpenId(tokenInfo[2]), RedisUtils.LOGIN_TOKEN_EXPIRE);
			}
			return status;
		}
		return false;
	}

	/**
	 * 用户退出登录
	 * @param token 用户令牌
	 */
	@Override
	public void logout(String token) {
		// 清除缓存
		redisUtils.delete(jwtUtils.tokenDecode(token)[0]);
		log.info("用户退出登录 token：{}", jwtUtils.getClaimByToken(token));
	}

	/**
	 * 根据字典值查询对应字典id
	 * @param itemText      字典值
	 * @return              返回字典id
	 */
	@Override
	public Integer findDictByItemText(String itemText) {
		return this.baseMapper.findDictByItemText(itemText);
	}

	/**
	 * 根据code换取openid校验是否是否存在
	 * @param code  用户凭证换取openid
	 * @return      存在返回true，不存在返回false
	 */
	@Override
	public boolean verifyUserExists(String code) {
		// 通过code凭证换取用户openid
		com.alibaba.fastjson.JSONObject jsonObject = loginCredentialsUtils.getCredentials(code);
		if ( jsonObject != null ) {
			String openid = jsonObject.getString("openid");
			AppUserEntity user = this.baseMapper.findUserByOpenId(openid);
			if ( user != null) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 用户实名认证
	 * @param reqVO 认证用户信息vo对象
	 * @return      认证通过 true 失败false
	 */
	@Override
	public boolean userRealNameAuth(AppUserRealAuthReqVO reqVO) {
		// 将base64字符串转成字节数组
		byte[] idCardFile = Base64.decode(reqVO.getIdCards()[0]);
		byte[] idFrontFile = Base64.decode(reqVO.getIdCards()[1]);
		// 解析身份证正反照，获取身份证信息
		Map<String, JSONObject> idCardInfoMap = ocrService.readIdCardInfo(idCardFile, idFrontFile);
		if ( idCardInfoMap.isEmpty() ) {
			return false;
		}
		// 封装身份证正反面信息
		IdCardEntity idCardFront = jsonUtils.idCardFront(idCardInfoMap.get("idCardFront"));
		// 用户信息对比
		if ( !idCardFront.getIdentityCard().equals(reqVO.getIdCardNumber())
				|| !idCardFront.getName().equals(reqVO.getName())) {
			log.error("【实名认证】用户实名认证失败，失败原因：{}，{}", idCardFront, reqVO);
			return false;
		}
		// TODO 此处应对接第三方电信运营商接口，验证手机号是否使用该身份证实名
		// 身份证信息验证成功完善该用户信息
		AppUserEntity appUserEntity = new AppUserEntity();
		appUserEntity.setIdentityCardNumber(idCardFront.getIdentityCard());
		appUserEntity.setGender(userService.findDictByItemText(idCardFront.getGender()));
		appUserEntity.setName(idCardFront.getName());
		userService.updateById(appUserEntity.setUserId(reqVO.getUserId()));
		// 清空用户缓存
		redisUtils.delete(reqVO.getUserId().toString());
		log.info("【实名认证】用户，{}，实名认证成功", appUserEntity);
		return true;
	}

	/**
	 * 用户绑定手机号码
	 * @param encryptedData 用户加密信息
	 * @param iv            加密算法向量
	 * @param token         登录用户token信息
	 * @return              绑定成功 true 失败false
	 */
	@Override
	public boolean userBindPhone(String encryptedData, String iv, String token) {
		// 解密token，获取当前登录用户的session_key，以及userId
		String[] tokens = jwtUtils.tokenDecode(token);
		String sessionKey = tokens[1];
		int userId = Integer.parseInt(tokens[0]);
		// 解密用户信息
		AesUtils aes = new AesUtils();
 		try{
		    byte[] resultByte = aes.decrypt(Base64.decode(encryptedData), Base64.decode(sessionKey),
				    Base64.decode(iv));
		    if ( resultByte != null && resultByte.length > 0) {
			    String jsons = null;
			    jsons = new String(resultByte, "UTF-8");
			    JSONObject userInfo = new JSONObject(jsons);
			    // 将用户微信绑定的手机号与系统进行绑定
			    userService.updateById(new AppUserEntity().setUserId(userId).setPhone(userInfo.getString("phoneNumber")));
			    log.info("【微信小程序】用户信息解密成功，info：{}", userInfo);
			    return true;
		    }
	    }catch (Exception e){
			e.printStackTrace();
	    }
		return false;
	}

	/**
	 * 识别证件信息
	 * @param reqVO 识别的证件类型，证件加密串
	 * @return      返回识别成功的证件信息
	 */
	@Override
	public R recognitionIdCardInfo(RecognitionIdCardInfoReqVO reqVO) {
		byte[] bytes = Base64.decode(reqVO.getIdCard());
		String idCardType = "";
		Object data = null;
		if (OcrConstants.IDCARD_FRONT.equals(reqVO.getIdCardType())) {
			idCardType = OcrConstants.IDCARD_FRONT;
			data = jsonUtils.idCardFront(aipOcr.idcard(bytes, OcrConstants.IDCARD_FRONT, null));
		}else {
			idCardType = OcrConstants.IDCARD_FRONT;
			data = jsonUtils.idCardFront(aipOcr.idcard(bytes, OcrConstants.IDCARD_BACK, null));
		}
		return R.ok().put("data", data);
	}

	/**
	 * 对添加的用户信息进行二次封装
	 * @param entity    用户对象
	 * @return          返回添加状态成功true，失败false
	 */
	@Override
	public boolean save(AppUserEntity entity) {
		return super.save(entity.setCreateTime(new Date()).setUserStatus(25));
	}
}
